/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.hd4ic.gui;

import edu.hd4ic.edu.hd4ic.data.ProcessingImageDataContainer;
import org.apache.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * @author morfant
 */
public class ApplicationData {

    private static final Logger LOGGER = Logger.getLogger(ApplicationData.class);
    public static final String APPLICATION_CONFIG_XML_FILEPATH = "application_config.xml";
    public static final String ROOT_NODE_NAME = "application_config";
    public static final String LAST_FILE_PATH_ELEMENT = "last_file_path";
    public static final String IMAGE_FILEPATH = "image_file_path";
    public static final String IMAGE_THRESHOLD = "image_threshold";
    public static final String ALGORITHM_TYPE="algorithm_type";
    public static final String INPUT_IMAGES = "input_images";
    public static final String IMAGE = "image";
    public static final String TEMPLATE_IMAGES = "template_images";
    public static final String CORNER_ALGORITHM_PARAMETERS = "corner_algorithm_parameters";
    public static final String KAPPA = "kappa";
    public static final String MIN_MEASURE = "min_measure";
    public static final String MIN_DISTANCE = "min_distance";
    public static final String ITERATION_NUMBER = "iteration_number";
    private Map<String, Integer> inputImageFilePathWitThresholdMap = new HashMap<String, Integer>();
    private Map<String, Integer> templateImageFilePathWitThresholdMap = new HashMap<String, Integer>();
    private Map<String, String[]> templateImageFilePathWithCornerParameters = new HashMap<String, String[]>();
    private String lastFilePath = "";
    private Document document = null;

    public ApplicationData() {
        SAXBuilder builder = new SAXBuilder();
        File file = new File(APPLICATION_CONFIG_XML_FILEPATH);
        if (file.exists()) {
            try {
                document = builder.build(file);
                Element rootNode = document.getRootElement();
                Element lastFilePathElement = rootNode.getChild(LAST_FILE_PATH_ELEMENT);
                if (lastFilePathElement != null) {
                    lastFilePath = lastFilePathElement.getText();
                } else {
                    rootNode.addContent(new Element(LAST_FILE_PATH_ELEMENT));
                }
                Element inputImageFilePathsElement = rootNode.getChild(INPUT_IMAGES);
                if (inputImageFilePathsElement != null) {
                    String filePath, threshold,type;
                    for (Element image : inputImageFilePathsElement.getChildren()) {
                        filePath = image.getChildText(IMAGE_FILEPATH);
                        threshold = image.getChildText(IMAGE_THRESHOLD);
                        if (filePath != null) {
                            inputImageFilePathWitThresholdMap.
                                    put(filePath, threshold != null ? Integer.parseInt(threshold) : null);
                        }
                    }
                } else {
                    rootNode.addContent(new Element(INPUT_IMAGES));
                }
                Element templateImageFilePathsElement = rootNode.getChild(TEMPLATE_IMAGES);
                if (templateImageFilePathsElement != null) {
                    String filePath, threshold;
                    String[] cornerParameters;
                    for (Element image : templateImageFilePathsElement.getChildren()) {
                        filePath = image.getChildText(IMAGE_FILEPATH);
                        threshold = image.getChildText(IMAGE_THRESHOLD);
                        if (filePath != null) {
                            templateImageFilePathWitThresholdMap.
                                    put(filePath, threshold != null ? Integer.parseInt(threshold) : null);
                        }
                        cornerParameters = new String[4];
                        cornerParameters[0] = image.getChildText(KAPPA);
                        cornerParameters[1] = image.getChildText(MIN_MEASURE);
                        cornerParameters[2] = image.getChildText(MIN_DISTANCE);
                        cornerParameters[3] = image.getChildText(ITERATION_NUMBER);
                        templateImageFilePathWithCornerParameters.put(filePath, cornerParameters);
                    }
                } else {
                    rootNode.addContent(new Element(TEMPLATE_IMAGES));
                }
            } catch (JDOMException e) {
                LOGGER.error("Ошибки при работе с application_config.xml!", e);
            } catch (IOException e) {
                LOGGER.error("Ошибка при загрузке application_config.xml!", e);
            }
        } else {
            createNewApplicationConfigDocument();
        }
    }

    private void createNewApplicationConfigDocument() {
        if (document == null) {
            document = new Document();
            Element rootNode = new Element(ROOT_NODE_NAME);
            Element lastFilePathElement = new Element(LAST_FILE_PATH_ELEMENT);
            Element inputImageFilePathsElement = new Element(INPUT_IMAGES);
            Element templateImageFilePathsElement = new Element(TEMPLATE_IMAGES);
            List<Element> baseElementOfData = new LinkedList<Element>();
            baseElementOfData.add(lastFilePathElement);
            baseElementOfData.add(inputImageFilePathsElement);
            baseElementOfData.add(templateImageFilePathsElement);
            rootNode.setContent(baseElementOfData);
            document.setRootElement(rootNode);
        }
    }

    public void storeApplicationConfig() {
        XMLOutputter xmlOutput = new XMLOutputter();

        // display nice nice
        xmlOutput.setFormat(Format.getPrettyFormat());

        try {
            xmlOutput.output(document, new FileWriter(new File(APPLICATION_CONFIG_XML_FILEPATH)));
        } catch (IOException e) {
            LOGGER.error("Ошибка при записе application_config.xml!", e);
        }
    }

    public String getLastFilePath() {
        return lastFilePath;
    }

    public void setLastFilePath(String newLastFilePath) {
        if (lastFilePath != null) {
            this.lastFilePath = newLastFilePath;
            Element rootElement = document.getRootElement();
            Element lastFilePathElement = rootElement.getChild(LAST_FILE_PATH_ELEMENT);
            lastFilePathElement.setText(newLastFilePath);
        } else {
            IllegalArgumentException exception =
                    new IllegalArgumentException("Последний посещенный путь не может быть равным null!");
            LOGGER.error("Ошибка обновления application_config.xml!", exception);
            throw exception;
        }
    }

    public Map<String, Integer> getInputImageFilePathWitThresholdMap() {
        return inputImageFilePathWitThresholdMap;
    }

    public Map<String, String[]> getTemplateImageFilePathWithCornerParameters() {
        return templateImageFilePathWithCornerParameters;
    }

    public void setInputImageFilePathWitThresholdMap(Map<String, Integer> inputImageFilePathWitThresholdMap) {
        if (inputImageFilePathWitThresholdMap != null) {
            this.inputImageFilePathWitThresholdMap = inputImageFilePathWitThresholdMap;
            Element rootElement = document.getRootElement();
            Element inputImageFilePathsElement = rootElement.getChild(INPUT_IMAGES);
            inputImageFilePathsElement.removeChildren(IMAGE);
            Element inputImageElement, inputImageFilePathElement, inputImageThresholdElement;
            Integer threshold;
            for (String inputImageFilePath : inputImageFilePathWitThresholdMap.keySet()) {
                inputImageElement = new Element(IMAGE);
                inputImageFilePathElement = new Element(IMAGE_FILEPATH);
                inputImageFilePathElement.setText(inputImageFilePath);
                inputImageElement.addContent(inputImageFilePathElement);
                threshold = inputImageFilePathWitThresholdMap.get(inputImageFilePath);
                if (threshold != null) {
                    inputImageThresholdElement = new Element(IMAGE_THRESHOLD);
                    inputImageThresholdElement.setText(threshold.toString());
                    inputImageElement.addContent(inputImageThresholdElement);
                }
                inputImageFilePathsElement.addContent(inputImageElement);
            }
        } else {
            IllegalArgumentException exception =
                    new IllegalArgumentException("Набор входных изобаржений не может быть равным null!");
            LOGGER.error("Ошибка обновления application_config.xml!", exception);
            throw exception;
        }
    }

    public Map<String, Integer> getTemplateImageFilePathWitThresholdMap() {
        return templateImageFilePathWitThresholdMap;
    }

    public void setTemplateImageFilePathWitThresholdMap(Map<String, Integer> templateImageFilePathWitThresholdMap,
                                                        Map<String, String[]> templateImageFilePathWithCornerParameters) {
        if (templateImageFilePathWitThresholdMap != null) {
            this.templateImageFilePathWitThresholdMap = templateImageFilePathWitThresholdMap;
            Element rootElement = document.getRootElement();
            Element templateImagesFilePathsElement = rootElement.getChild(TEMPLATE_IMAGES);
            templateImagesFilePathsElement.removeChildren(IMAGE);
            Element templateImageElement, templateImageFilePathElement, templateImageThresholdElement;
            Element kappa, minMeasure, minDistance, iterationNumber;
            Integer threshold;
            String[] cornerParameters;
            for (String inputImageFilePath : templateImageFilePathWitThresholdMap.keySet()) {
                templateImageElement = new Element(IMAGE);
                templateImageFilePathElement = new Element(IMAGE_FILEPATH);
                templateImageFilePathElement.setText(inputImageFilePath);
                templateImageElement.addContent(templateImageFilePathElement);
                threshold = templateImageFilePathWitThresholdMap.get(inputImageFilePath);
                if (threshold != null) {
                    templateImageThresholdElement = new Element(IMAGE_THRESHOLD);
                    templateImageThresholdElement.setText(threshold.toString());
                    templateImageElement.addContent(templateImageThresholdElement);
                }
                cornerParameters = templateImageFilePathWithCornerParameters.get(inputImageFilePath);
                if (cornerParameters != null) {
                    kappa = new Element(KAPPA);
                    kappa.setText(cornerParameters[0]);
                    minMeasure = new Element(MIN_MEASURE);
                    minMeasure.setText(cornerParameters[1]);
                    minDistance = new Element(MIN_DISTANCE);
                    minDistance.setText(cornerParameters[2]);
                    iterationNumber = new Element(ITERATION_NUMBER);
                    iterationNumber.setText(cornerParameters[3]);
                    templateImageElement.addContent(kappa);
                    templateImageElement.addContent(minMeasure);
                    templateImageElement.addContent(minDistance);
                    templateImageElement.addContent(iterationNumber);
                }
                templateImagesFilePathsElement.addContent(templateImageElement);
            }
        } else {
            IllegalArgumentException exception =
                    new IllegalArgumentException("Набор входных изобаржений не может быть равным null!");
            LOGGER.error("Ошибка обновления application_config.xml!", exception);
            throw exception;
        }
    }
}
